// 版权归Go作者所有。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package s390x

import (
	"math/bits"
)

// RotateParams表示“rotate 
// then…selected bits指令”所需的立即数。
// 
// 起始值和结束值是表示屏蔽区域的索引。它们是包含的，并且是大的-
// endian顺序（位0是MSB，位63是LSB）。他们可能会绕过去。（
// 
// /Amount值表示将
// 输入向左旋转的量。请注意，此旋转是在使用遮罩区域之前执行的。
type RotateParams struct {
	Start  uint8 // 大端开始位索引[0..63]
	End    uint8 // 大端结束位索引[0..63]
	Amount uint8 // 左旋转量
}

// NewRotateParams创建一组参数，表示
// 左旋转量，以及在所提供的开始和结束索引（包括）之间选择的位
// 。
// 
// 开始和结束索引以及旋转量必须全部在0-63范围内，否则此函数将死机。
func NewRotateParams(start, end, amount uint8) RotateParams {
	if start&^63 != 0 {
		panic("start out of bounds")
	}
	if end&^63 != 0 {
		panic("end out of bounds")
	}
	if amount&^63 != 0 {
		panic("amount out of bounds")
	}
	return RotateParams{
		Start:  start,
		End:    end,
		Amount: amount,
	}
}

// RotateLeft生成一组新的参数，旋转量
// 增加给定值。所选位保持不变。
func (r RotateParams) RotateLeft(amount uint8) RotateParams {
	r.Amount += amount
	r.Amount &= 63
	return r
}

// OutMask提供一个表示所选位的掩码。
func (r RotateParams) OutMask() uint64 {
	// 注意：对于引导编译器
	z := uint8(63-r.End+r.Start) & 63 // 掩码中的零位数
	return bits.RotateLeft64(^uint64(0)<<z, -int(r.Start))
}

// InMask提供了一个掩码，表示相对于源值（即预旋转）的所选位。
func (r RotateParams) InMask() uint64 {
	return bits.RotateLeft64(r.OutMask(), -int(r.Amount))
}

// OutMerge尝试生成一组新的参数，表示所选位和提供的掩码之间的交集。
// 如果交叉点不可表示（0或不连续），则返回nil 
// 值。
func (r RotateParams) OutMerge(mask uint64) *RotateParams {
	mask &= r.OutMask()
	if mask == 0 {
		return nil
	}

	// 规范化掩码，使设置的位左对齐
	o := bits.LeadingZeros64(^mask)
	mask = bits.RotateLeft64(mask, o)
	z := bits.LeadingZeros64(mask)
	mask = bits.RotateLeft64(mask, z)

	// 检查规范化掩码是否连续
	l := bits.LeadingZeros64(^mask)
	if l+bits.TrailingZeros64(mask) != 64 {
		return nil
	}

	// 更新开始和结束位置（旋转量保持不变）
	r.Start = uint8(o+z) & 63
	r.End = (r.Start + uint8(l) - 1) & 63
	return &r
}

// InMerge尝试生成一组表示
// 所选位和提供的掩码之间的交集的新参数
// 适用于源值（即预旋转）。
// 如果交叉点不可表示（0或不连续），则返回nil 
// 值。
func (r RotateParams) InMerge(mask uint64) *RotateParams {
	return r.OutMerge(bits.RotateLeft64(mask, int(r.Amount)))
}

func (RotateParams) CanBeAnSSAAux() {}
